package com.entropy.code.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;

import javax.sql.DataSource;

/**
 * 数据源配置
 *
 * @author xiachao
 */
@Configuration
@EnableTransactionManagement
public class DalConfig implements TransactionManagementConfigurer, ApplicationContextAware {

    private PlatformTransactionManager transactionManager;

    private DruidDataSource dataSource;

    private static String url = "spring.datasource.url";
    private static final String username = "spring.datasource.username";
    private static final String password = "spring.datasource.password";
    private static final String driverClassName = "spring.datasource.driverClassName";
    private static final String initialSize = "spring.datasource.initialSize";
    private static final String minIdle = "spring.datasource.minIdle";
    private static final String maxWait = "spring.datasource.maxWait";
    private static final String maxActive = "spring.datasource.maxActive";
    private static final String timeBetweenEvictionRunsMillis = "spring.datasource.timeBetweenEvictionRunsMillis";
    private static final String minEvictableIdleTimeMillis = "spring.datasource.minEvictableIdleTimeMillis";
    private static final String validationQuery = "spring.datasource.validationQuery";
    private static final String testWhileIdle = "spring.datasource.testWhileIdle";
    private static final String testOnBorrow = "spring.datasource.testOnBorrow";
    private static final String testOnReturn = "spring.datasource.testOnReturn";

    private static final String ALIASES_PACKAGE = "com.entropy.code.dal.model";

    private static final String MAPPER_SCAN_PACKAGE = "com.entropy.code.dal.mapper";

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(this.dataSource);
        Resource configLocation = new ClassPathResource("mybatis/mybatis-config.xml");
        sessionFactoryBean.setConfigLocation(configLocation);
        sessionFactoryBean.setTypeAliasesPackage(ALIASES_PACKAGE);
        Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/sqlmap/*.xml");
        sessionFactoryBean.setMapperLocations(resources);
        return sessionFactoryBean.getObject();
    }

    private DataSource buildDataSource(Environment env) {
        this.dataSource = new DruidDataSource();
        this.dataSource.setUrl(env.getProperty(url));
        this.dataSource.setUsername(env.getProperty(username));
        this.dataSource.setPassword(env.getProperty(password));
        this.dataSource.setDriverClassName(env.getProperty(driverClassName));
        this.dataSource.setInitialSize(Integer.valueOf(env.getProperty(initialSize, "10")));
        this.dataSource.setMinIdle(Integer.valueOf(env.getProperty(minIdle, "5")));
        this.dataSource.setMaxWait(Integer.valueOf(env.getProperty(maxWait, "60")));
        this.dataSource.setMaxActive(Integer.valueOf(env.getProperty(maxActive, "60000")));
        this.dataSource.setTestWhileIdle(Boolean.valueOf(env.getProperty(testWhileIdle)));
        this.dataSource.setTestOnBorrow(Boolean.valueOf(env.getProperty(testOnBorrow)));
        this.dataSource.setTestOnReturn(Boolean.valueOf(env.getProperty(testOnReturn)));
        this.dataSource.setValidationQuery(env.getProperty(validationQuery));
        this.dataSource.setTimeBetweenEvictionRunsMillis(Integer.valueOf(env.getProperty(timeBetweenEvictionRunsMillis, "3000")));
        this.dataSource.setMinEvictableIdleTimeMillis(Integer.valueOf(env.getProperty(minEvictableIdleTimeMillis, "300000")));
        return dataSource;
    }

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        mapperScannerConfigurer.setBasePackage(MAPPER_SCAN_PACKAGE);
        return mapperScannerConfigurer;
    }

    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        this.transactionManager = new DataSourceTransactionManager(this.dataSource);
        return transactionManager;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.buildDataSource(applicationContext.getEnvironment());
    }
}
